﻿using System;
using System.Collections.Generic;
using System.Linq;
using CI;
using CI.Mesopotamia.Dal;
using CI.Misc;
using NUnit.Framework;
using CI.Interfaces;
using Rhino.Mocks;

namespace Mesopotamia.UnitTests
{
    [TestFixture]
    public class XMLDALTests
    {
        /// <summary>
        /// Main xml dal to test with
        /// </summary>
        private CI.DAL.XMLDAL _xmlDal;
        private IHostingEnvironment _hostingEnvironment;
        private string _environmentName;
        private MockRepository _mocks;
        private CI.Mesopotamia.Scenario _scenario;
        private readonly SimEnv _simEnv = SimEnv.Instance;

        [SetUp]
        public void Setup()
        {
            _xmlDal = new CI.DAL.XMLDAL();
            _environmentName = "Mesopotamia";
            _mocks = new MockRepository();
            _hostingEnvironment = _mocks.DynamicMock<IHostingEnvironment>();
            _mocks.DynamicMock<IHostingEnvironmentPhysical>();
        }

        /// <summary>
        /// Test to make sure it throw and exception on null or empty exception string
        /// </summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "environment")]
        public void LoadNullEnvironmentException()
        {
            _xmlDal.LoadHostingEnvironment(null, _hostingEnvironment, 0, new List<Guid>());
        }

        /// <summary>
        /// Test to make sure it throw and exception on null hosting environment
        /// </summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "hostEnvironment")]
        public void LoadNullHostingEnvironmentException()
        {
            _xmlDal.LoadHostingEnvironment(_environmentName, null, 0, new List<Guid>());
        }

        /// <summary>
        /// Test to make sure it throw and exception on null or empty exception string
        /// </summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "environment")]
        public void SaveOrganismsNullEnvironmentException()
        {
            _xmlDal.SaveHostingEnvironment(null, _hostingEnvironment, 0);
        }

        /// <summary>
        /// Test to make sure it throw and exception on null hosting environment
        /// </summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "hostEnvironment")]
        public void SaveOrganismsNullHostingEnvironmentException()
        {
            _xmlDal.SaveHostingEnvironment(_environmentName, null, 0);
        }

        /// <summary>
        /// Test to check saving to xml
        /// </summary>
        [Test]
        public void XMLSaveTestTrue()
        {
            IDAL dal = new TestDAL();
            IHostingEnvironment _hostingEnvironment = new CI.Mesopotamia.MSRBHost(new MockHostingEnvironmentPhysical(), new CI.Mesopotamia.ScenarioLocalXML());
            _hostingEnvironment.FitnessFunction = new MockFitnessFunction();
            Assert.IsNotNull((dal.LoadHostingEnvironment(_environmentName, _hostingEnvironment, 0, new List<Guid>()) != null), "Unable to load");
            Assert.IsTrue(_xmlDal.SaveHostingEnvironment(_environmentName, _hostingEnvironment, 0), "Unable to save to xml");
        }

        /// <summary>
        /// Test to check loading of xml
        /// </summary>
        [Test]
        public void XMLLoadTestTrue()
        {
            // create a hosting environment
            IHostingEnvironment _hostingEnvironment = new CI.Mesopotamia.MSRBHost(new MockHostingEnvironmentPhysical(), new CI.Mesopotamia.ScenarioLocalXML());
            _hostingEnvironment.FitnessFunction = new MockFitnessFunction();
            // save it
            _xmlDal.SaveHostingEnvironment(_environmentName, _hostingEnvironment, 0);
            // try loading it back in
            _hostingEnvironment = _xmlDal.LoadHostingEnvironment(_environmentName, _hostingEnvironment, 0, new List<Guid>());
            Assert.IsNotNull(_hostingEnvironment, "Unable to load");
        }

        private void CreateScenario()
        {
            _scenario = new CI.Mesopotamia.ScenarioLocalXML();
            _hostingEnvironment = new CI.Mesopotamia.MSRBHost(new MockHostingEnvironmentPhysical(), _scenario);
            _scenario.FitnessFunction = typeof(CI.Mesopotamia.CollisionDetection).ToString();
            _scenario.ScenarioName = "test";
            _scenario.ScenarioDescription = "The evolutionary objective is for the fattest one to reproduce and evolve";
            _scenario.ManifestFile = "InABox.Manifest.xml";
            _scenario.BoundryXRadiusMax = 3.2f;
            _scenario.BoundryYRadiusMax = 2.5f;
            _scenario.BoundryZRadiusMax = 3.2f;
            _scenario.SimulationRestrictions = typeof(CI.Mesopotamia.SurvivalFattest).ToString();
            _scenario.RequiredOrganisms = new List<IScenarioEntityRequirements>();
            _scenario.FallBackOrganisms.Add(new CI.Organism.Organism(_hostingEnvironment));
            _scenario.FallBackOrganisms.Add(new CI.Organism.Organism(_hostingEnvironment));
        }

        /// <summary>
        /// Test to check loading of xml
        /// </summary>
        [Test]
        public void XMLLoadSaveCompareTrue()
        {
            CreateScenario();

            var filePath = System.IO.Path.Combine(System.Environment.CurrentDirectory, "test");
            IHostingEnvironment _saved = new CI.Mesopotamia.MSRBHost(new MockHostingEnvironmentPhysical(), _scenario);
            var testDAL = new TestDAL();
            _saved = testDAL.LoadHostingEnvironment(filePath, _saved, 10, new List<Guid>());
            _saved.FitnessFunction = new MockFitnessFunction();

            // save the environment
            var xmlDAL = new CI.DAL.XMLDAL();
            _xmlDal.SaveHostingEnvironment(filePath, _saved, 10);

            IHostingEnvironment _loaded = new CI.Mesopotamia.MSRBHost(new MockHostingEnvironmentPhysical(), new CI.Mesopotamia.ScenarioLocalXML());
            _loaded = _xmlDal.LoadHostingEnvironment(filePath, _loaded, 10, new List<Guid>());

            List<CI.Organism.Organism> saved = _saved.Organisms.Cast<CI.Organism.Organism>().ToList();
            List<CI.Organism.Organism> loaded = _loaded.Organisms.Cast<CI.Organism.Organism>().ToList();

            Assert.Greater(saved.Count, 0);
            Assert.IsTrue(CompareOrgList(saved, loaded));
        }

        /// <summary>
        /// Compare two lists to make sure they are the same
        /// </summary>
        /// <param name="list1"></param>
        /// <param name="list2"></param>
        /// <returns></returns>
        public bool CompareOrgList(List<CI.Organism.Organism> list1, List<CI.Organism.Organism> list2)
        {
            // make sure they are both defined
            if (list1 == null)
                return false;
            if (list2 == null)
                return false;
            // check the counts
            if (list1.Count != list2.Count)
                return false;

            // go through the list
            foreach (CI.Organism.Organism organism in list1)
            {

                #region Check to make sure its not already in the list
                // if it already in the list dont add it
                CI.Organism.Organism foundOrganism = null;
                try
                {
                    foundOrganism = list2.First(organismFind => organismFind.Guid == organism.Guid);
                }
                catch (InvalidOperationException)
                {
#if DEBUG
                    return false;
#endif
                }
                #endregion

                if (!organism.EqualsValueTypes(foundOrganism))
                    return false;
            }
            return true;
        }

        ///// <summary>
        ///// Test to check loading of xml and running
        ///// </summary>
        //[Test]
        //public void XMLLoadAndRunTrue()
        //{
        //    CI.Mesopotamia.ScenarioHostBootstrap _bootStrap = new CI.Mesopotamia.ScenarioHostBootstrap();
        //    _bootStrap.DAL = _xmlDal;
        //    _bootStrap.Start(new MockHostingEnvironmentPhysical(), null, null);
        //}


        [TearDown]
        public void TearDown()
        {
        }

    }

}
